package pprg.gui;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.util.Observable;
import java.util.Observer;

import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.Timer;

import pprg.core.GameOfLife;


public class GameOfLifeGUI implements Observer {

	private GameOfLife gol;
	private JFrame frame;
	private JPanel mainPanel;
	private GameOfLifePanel golPanel;
	private JPanel controlPanel;
	private JButton startButton;
	private JButton clearButton;
	private JTextField txtHertz;
	private JLabel lblHertz;
	private JCheckBox checkBoxParallel;
	private JLabel lblThreads;
	private JTextField txtThreads;
	private JButton btnCreateRandomPopulation;
	private JLabel lblVialPercentage;
	private JTextField txtVialPercentage;
	

	private boolean running;
	private Timer timer;

	private static double initPopulationChance = 0.1;
	private boolean parallel;
	private int hertz = 25;
	private int numThreads = 8;
	private static int arraySize = 100;
	
	static GameOfLifeGUI gui;

	public GameOfLifeGUI(GameOfLife gol) {
		this.gol = gol;
		gol.addObserver(this);
		init();
		createTimer();
		addListener();
	}

	private void createTimer() {
		timer = new Timer((int) (1000 * (1 / (double) hertz)), (e) -> {
			playSequential();
		});
	}

	public static void main(String[] args) {
		GameOfLife gol = new GameOfLife(arraySize, initPopulationChance);
		gui = new GameOfLifeGUI(gol);
	}

	private void init() {
		mainPanel = new JPanel();
		golPanel = new GameOfLifePanel(gol);
		mainPanel.setLayout(new BorderLayout());
		mainPanel.add(golPanel, BorderLayout.CENTER);
		controlPanel = new JPanel();
		lblVialPercentage = new JLabel("Living Chance");
		txtVialPercentage = new JTextField("" + initPopulationChance);
		txtVialPercentage.setPreferredSize(new Dimension(80, 30));
		controlPanel.add(lblVialPercentage);
		controlPanel.add(txtVialPercentage);
		btnCreateRandomPopulation = new JButton("Create Population");
		controlPanel.add(btnCreateRandomPopulation);
		startButton = new JButton("Start");
		controlPanel.add(startButton);
		clearButton = new JButton("Clear");
		controlPanel.add(clearButton);
		lblHertz = new JLabel("Frequenz [Hz]");
		controlPanel.add(lblHertz);
		txtHertz = new JTextField(String.valueOf(hertz));
		txtHertz.setPreferredSize(new Dimension(80, 30));
		controlPanel.add(txtHertz);
		checkBoxParallel = new JCheckBox("Calculate Parallel");
		lblThreads = new JLabel("# Threads");
		txtThreads = new JTextField(numThreads);
		txtThreads.setPreferredSize(new Dimension(80, 30));
		controlPanel.add(checkBoxParallel);
		controlPanel.add(lblThreads);
		controlPanel.add(txtThreads);
		mainPanel.add(controlPanel, BorderLayout.SOUTH);
		frame = new JFrame();
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.add(mainPanel);
		frame.setPreferredSize(new Dimension(1200, 1000));
		frame.pack();
		frame.setVisible(true);
	}

	private void addListener() {

		ActionListener createPopulationListener = new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				if (btnCreateRandomPopulation.isEnabled()) {
					gol.createRandomStartGeneration(initPopulationChance);
				}
			}
		};
		btnCreateRandomPopulation.addActionListener(createPopulationListener);

		ActionListener startStopListener = new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				if (!running) {
					running = true;
					startButton.setText("Stop");
					clearButton.setEnabled(false);
					checkBoxParallel.setEnabled(false);
					btnCreateRandomPopulation.setEnabled(false);
					if (!parallel) {
						timer.start();
					} else {
						gol.parallelGameOfLife(numThreads, true,
								Integer.MAX_VALUE);
					}
				} else {
					running = false;
					clearButton.setEnabled(true);
					checkBoxParallel.setEnabled(true);
					btnCreateRandomPopulation.setEnabled(true);
					startButton.setText("Start");
					if (!parallel) {
						timer.stop();
					} else {
						gol.stopParallelCalculation();
					}
				}
			}
		};
		startButton.addActionListener(startStopListener);

		ActionListener clearWorldlistener = new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				clear();
			}
		};
		clearButton.addActionListener(clearWorldlistener);

		ActionListener frequencyListener = new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				try {
					hertz = Integer.parseInt(txtHertz.getText());
					if (running) {
						timer.stop();
					}
					createTimer();
					if (running) {
						timer.start();
					}

				} catch (Exception ex) {
					System.out.println("Enter an int");
				}
			}
		};
		txtHertz.addActionListener(frequencyListener);

		ComponentAdapter golSizeListener = new ComponentAdapter() {

			@Override
			public void componentResized(ComponentEvent e) {
				int width = (int) Math.floor(golPanel.getWidth());
				int height = (int) Math.floor(golPanel.getHeight());
				if (gol != null) {
					Dimension newSize = new Dimension(arraySize
							* (width / arraySize), arraySize
							* (height / arraySize));
					golPanel.setSize(newSize);
				}
			}

		};
		mainPanel.addComponentListener(golSizeListener);

		ActionListener parallelComputationEnableListener = new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				if (checkBoxParallel.isSelected()) {
					parallel = true;
					txtThreads.setEnabled(true);
				} else {
					parallel = false;
					txtThreads.setEnabled(false);
				}
			}
		};
		checkBoxParallel.addActionListener(parallelComputationEnableListener);

		ActionListener numThreadsListener = new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				if (txtThreads.isEnabled()) {
					try {
						numThreads = Integer.parseInt(txtThreads.getText());
					} catch (Exception ex) {
						System.out.println("Enter an int");
					}
				}
			}
		};
		txtThreads.addActionListener(numThreadsListener);

		ActionListener livingChanceListener = new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				try {
					initPopulationChance = Double.parseDouble(txtVialPercentage
							.getText());
				} catch (Exception ex) {
					System.out.println("Enter an double");
				}
			}
		};
		txtVialPercentage.addActionListener(livingChanceListener);
		
			
		
	}

	private void playSequential() {
		gol.sequentialIteration(true);
	}

	private void clear() {
		gol.setArray(new boolean[arraySize][arraySize]);
		golPanel.repaint();
	}

	@Override
	public void update(Observable o, Object arg) {
		golPanel.repaint();
	}
	
	public void updateGol(GameOfLife newGol) {
		this.gol = newGol;
		newGol.addObserver(this);
		golPanel = new GameOfLifePanel(newGol);
		controlPanel.updateUI();
	}
}
